home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / video / vidmap / vidmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  18.0 KB  |  708 lines

  1. /*
  2.  * Copyright 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*----------------------------------------------------------------
  18.  * 
  19.  *  vidmap - live video and movie video texture mapping example using
  20.  *           both VL (SGI Video Library) and MV (SGI movie library).
  21.  *  
  22.  *  08/93  John Magdziarz, Silicon Graphics, Inc.
  23.  * 
  24.  *----------------------------------------------------------------*/
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <X11/Xlib.h>
  29. #include <gl/gl.h>
  30. #include <gl/device.h>
  31. #include <gl/image.h>
  32. #include <gl/glws.h>
  33. #include "glxhelper.h"
  34. #include <sys/time.h>
  35. #include <sys/fcntl.h>
  36. #include <X11/keysym.h>
  37. #include <movie.h>
  38. #include <vl/vl.h>
  39.  
  40.  
  41. #define RGB_COMP        4   /* select a 4 component texture */
  42. #define DEF_FRAME_RATE  6
  43. #define MAX_RATE        30
  44. #define DEF_BUF_SIZE    2
  45. #define X_KEYMAGIC      8               /* One byte offset in keycodes */
  46. #define XKEY_TO_GLKEY(x)        ((x) - X_KEYMAGIC + 1)
  47.  
  48. VLServer    svr;
  49. VLPath        path;
  50. VLDevList   devlist;
  51. VLNode      src;
  52. VLNode      drn;
  53. VLBuffer    buffer;
  54. int        devicenum = -1;
  55. char        *deviceName;
  56. int        vin = 0;
  57. int imageCount = 1;
  58. VLTransferDescriptor xferDesc;
  59. VLControlValue val;
  60.  
  61. int imgWidth = 320;
  62. int imgHeight = 240;
  63. int width[] = { 512, 256, 128, 64, 32 };
  64. int height[] = { 256, 128, 64, 32, 16 };
  65.  
  66. float minFilter[] = { TX_POINT, TX_BILINEAR, 
  67.                     TX_MIPMAP_POINT, TX_MIPMAP_LINEAR, 
  68.                     TX_MIPMAP_BILINEAR, TX_MIPMAP_TRILINEAR };
  69.  
  70. char *minFilterName[] = { "TX_POINT", "TX_BILINEAR", 
  71.                     "TX_MIPMAP_POINT", "TX_MIPMAP_LINEAR",            
  72.                     "TX_MIPMAP_BILINEAR", "TX_MIPMAP_TRILINEAR" };
  73.  
  74. float magFilter[] = { TX_POINT, TX_BILINEAR,  TX_BILINEAR_LEQUAL,
  75.             TX_TRILINEAR, TX_BICUBIC,
  76.                     TX_SHARPEN, TX_ADD_DETAIL };
  77.  
  78. char *magFilterName[] = { "TX_POINT", "TX_BILINEAR" };
  79.  
  80. float texprops[] = { TX_MINFILTER, TX_POINT,
  81.             TX_MAGFILTER, TX_POINT,
  82.             TX_WRAP, TX_REPEAT, TX_NULL};
  83.  
  84. float tevprops[] = { TV_NULL };
  85.  
  86. int         captureFormat;
  87. Boolean     video = FALSE;
  88. Boolean     oneComp = TRUE;
  89. ulong       transferSize;
  90. char        *ringBuffer = 0;
  91. ulong       *rgbFrame;
  92. int         frameSize;
  93. static char *_progName;
  94. int        xWinSize = 0, yWinSize = 0;
  95. int         forced_node = 0;
  96. Boolean     initTextureParams = TRUE;
  97. int         zoom = 2;
  98. Boolean     debug = FALSE;
  99. Boolean     newImg = False;
  100. float       transy = -80;
  101.  
  102. MVid        mymovie;
  103. MVid        imgTrack;
  104. int         movieLen;
  105. char        *moviefn;
  106.  
  107. Display* dpy; 
  108. int scrn;
  109. Window win;
  110. XEvent event;
  111. Boolean grabNew = TRUE;
  112. Boolean moving = FALSE;
  113. Boolean buttonIsPressed = FALSE;
  114. Boolean bltImg = FALSE;
  115. int minFiltIndex = 0;
  116. int magFiltIndex = 0;
  117. int sizeIndex = 1;
  118. struct timeval starttime, endtime;
  119. int nframes = 0;
  120. struct timeval starttime, endtime;
  121. Boolean reportPerf = False;
  122. Screencoord xorg, xwidth, xmax,  yorg, yheight, ymax;
  123.  
  124. char *controlStr = "\
  125.     Mouse controls:\n\
  126. \n\
  127.     Mouse rotates the plane around the x and y axes.\n\
  128.     Button down while moving mouse zooms in and out.\n\
  129. \n\
  130.     Keyboard controls:\n\
  131. \n\
  132.       b   - toggles between texture mapping and fast bit-blitting (lrectwrite)\n\
  133.       g   - toggles on/off of grabbing new frames\n\
  134.       p   - toggles performance reporting (fps every 10 frames) default off\n\
  135.       m   - cycles through the texture map magnification filters\n\
  136.       n   - cycles through the texture map minification filters\n\
  137.       q   - toggles multiple images on same plane (1/4 texture map)\n\
  138.       ESC - exit\n";
  139.  
  140. unsigned long *image, *imageInter; 
  141.  
  142. /* Define texture and vertex coordinates */
  143. float t0[2] = {0., 0.},  v0[3] = {-32., 24.,0.};
  144. float t1[2] = {1., 0.},  v1[3] = {32., 24.,0.};
  145. float t2[2] = {1., 1.},  v2[3] = {32., -24.,0.};
  146. float t3[2] = {0., 1.},  v3[3] = {-23., -24.,0.};
  147.  
  148.  
  149. void
  150. printControls()
  151. {
  152.   printf("%s", controlStr);
  153. }
  154.  
  155. initVideo()
  156. {
  157.    VLNode nodes[2];
  158.    int vidsrc = 0;
  159.    int frameSize;
  160.    VLFraction fval;
  161.    
  162.     if (!(svr = vlOpenVideo(""))) {
  163.     fprintf(stderr, "%s: couldn't open video\n", _progName);
  164.     exit(1);
  165.     }
  166.  
  167.     if (vlGetDeviceList(svr, &devlist) < 0) {
  168.     fprintf(stderr,"%s: getting device list.\n",_progName);
  169.     exit(1);
  170.     }
  171.  
  172.  
  173.     drn = vlGetNode(svr, VL_DRN, VL_MEM, VL_ANY);
  174.     if (forced_node == 0)
  175.     src = vlGetNode(svr, VL_SRC, VL_VIDEO, VL_ANY);
  176.     else
  177.     src = vlGetNode(svr, VL_SRC, VL_VIDEO, vin);
  178.  
  179.  
  180.     /* create the path (just grab the first device) */
  181.     if ((devicenum >= (int)devlist.numDevices) || (devicenum < -1))
  182.     {
  183.     if (devlist.numDevices == 1)
  184.         fprintf(stderr,"%s: The device number must be 0\n",_progName);
  185.     else
  186.         fprintf(stderr,"%s: The device number must be between 0 and %d\n",
  187.             _progName, devlist.numDevices-1);
  188.     exit(1);
  189.     }
  190.  
  191.     drn = vlGetNode(svr, VL_DRN, VL_MEM, VL_ANY);
  192.     if (forced_node == 0)
  193.     src = vlGetNode(svr, VL_SRC, VL_VIDEO, VL_ANY);
  194.     else
  195.     src = vlGetNode(svr, VL_SRC, VL_VIDEO, vin);
  196.  
  197.     if (devicenum == -1)
  198.     {
  199.         if ((path = vlCreatePath(svr, VL_ANY, src, drn)) < 0) {
  200.           vlPerror(_progName);
  201.       exit(1);
  202.     }
  203.     devicenum = vlGetDevice(svr, path);
  204.     deviceName = devlist.devices[devicenum].name;
  205.     }
  206.     else
  207.     {
  208.     deviceName = devlist.devices[devicenum].name;
  209.     if ((path = vlCreatePath(svr, devicenum, src, drn)) < 0) {
  210.         vlPerror(_progName);
  211.         exit(1);
  212.     }
  213.     }
  214.  
  215.  
  216.     if (vlSetupPaths(svr, (VLPathList)&path, 1, VL_SHARE, VL_SHARE) < 0)
  217.     {
  218.     vlPerror(_progName);
  219.     exit(1);
  220.     }
  221.  
  222.     /* get the name of the device we're using */
  223.  
  224.     deviceName = devlist.devices[devicenum].name;
  225.  
  226.     vlGetControl(svr, path, drn, VL_OFFSET, &val);
  227.     if (debug)
  228.       printf("X offset = %d  Y offset = %d\n", val.xyVal.x, val.xyVal.y);
  229.  
  230.     val.fractVal.numerator = 1;
  231.     val.fractVal.denominator = zoom;
  232.     vlSetControl(svr, path, drn, VL_ZOOM, &val);
  233.     
  234.     vlGetControl(svr, path, drn, VL_ZOOM, &val);
  235.     if (debug)
  236.       printf("zoom = %d/%d\n", val.fractVal.numerator, val.fractVal.denominator);
  237.  
  238.     vlGetControl(svr, path, drn, VL_SIZE, &val);
  239.     
  240.     imgWidth = val.xyVal.x;
  241.     imgHeight = val.xyVal.y;
  242.  
  243.     fprintf(stderr, "grabbing size %dx%d\n", imgWidth, imgHeight);
  244.  
  245.  
  246.     val.intVal = VL_PACKING_RGB_8;
  247.     vlSetControl(svr, path, drn, VL_PACKING, &val);
  248.  
  249.     /* specify what path-related events we want to receive */
  250.     vlSelectEvents(svr, path, VLTransferCompleteMask);
  251.  
  252.     frameSize = vlGetTransferSize(svr, path);
  253.  
  254.     buffer = vlCreateBuffer(svr, path, drn, imageCount);
  255.     if (buffer == NULL)
  256.     {
  257.     perror("creating buffer");
  258.     exit(1);
  259.     }
  260.     /* now the vl will talk to the hardware to setup the path */
  261.  
  262.     vlRegisterBuffer(svr, path, drn, buffer);
  263.  
  264.     xferDesc.mode = VL_TRANSFER_MODE_CONTINUOUS;
  265.     xferDesc.count = 1;
  266.     xferDesc.delay = 0;
  267.     xferDesc.trigger = VLTriggerImmediate;
  268.     
  269.     vlBeginTransfer(svr, path, 0, NULL);
  270. }
  271.  
  272.  
  273. static void set_entry (GLXconfig* ptr, int b, int m, int a)
  274. {
  275.     ptr->buffer = b;
  276.     ptr->mode = m;
  277.     ptr->arg = a;
  278. }
  279.  
  280.  
  281. initMovie()
  282. {
  283.     int moviefd, maxfd, xfd, filefd;
  284.     fd_set fdset, loopfdset;
  285.  
  286.     if (mvIsMovieFile(moviefn) == DM_FALSE) {
  287.         fprintf(stderr, "%s: %s is not a movie file, exiting.\n",
  288.                 _progName, moviefn);
  289.         exit(-1);
  290.     }
  291.     else if ((mvOpenFile(moviefn, O_RDONLY, &mymovie)) < 0) {
  292.         fprintf(stderr, "could not open movie file %s\n", moviefn);
  293.         exit(-1);
  294.     }
  295.     
  296.     mvFindTrackByMedium( mymovie, DM_IMAGE, &imgTrack);
  297.     movieLen = mvGetTrackLength(imgTrack);    
  298.     imgWidth = mvGetImageWidth(imgTrack);
  299.     imgHeight = mvGetImageHeight(imgTrack);
  300.     
  301.     frameSize = imgWidth * imgHeight * sizeof(ulong);
  302.     rgbFrame = (ulong *)malloc(frameSize);
  303.  
  304.     /* Bind the GL/X window we just created to the movie. */
  305.     if (mvBindWindow(mymovie, dpy, win) < 0) {
  306.         fprintf(stderr, "could not bind movie to window\n");
  307.         exit(0);
  308.     }
  309.  
  310.     /* Get the file descriptor responsible for communicating the
  311.        events we'll get back from the movie player */
  312.     if (mvGetEventFD(&moviefd) < 0) {
  313.         fprintf(stderr, "could not get movie fd\n");
  314.         exit(0);
  315.     }
  316.  
  317.  
  318.     /* decide which movie events we're interested in hearing. */
  319.     mvSetSelectEvents(MV_EVENT_MASK_FRAME | MV_EVENT_MASK_STOP |
  320.                       MV_EVENT_MASK_ERROR);
  321.  
  322.     mvSetFrameDisplay(FALSE);
  323.     mvSetCurrentFrame(mymovie, 0);
  324.     mvSetLoopMode(mymovie, MV_LOOP_CONTINUOUSLY);
  325. }
  326.  
  327.  
  328. int createVideoWindow(int width, int height)
  329. {
  330.     /* Create an X window configured for GL rendering, using
  331.        the helper functions defined in glxhelper.c */
  332.     win = GLXCreateWindow(dpy, RootWindow(dpy, DefaultScreen(dpy)),
  333.                           100, 100, width, height, 0, GLXrgbDoubleBuffer);
  334.      if (GLXwinset(dpy, win) < 0) {
  335.         fprintf(stderr, "\nGLXwinset is < 0\n");
  336.         exit(-1);
  337.      }
  338.  
  339.     XSelectInput( dpy, win, ExposureMask | StructureNotifyMask | ButtonPressMask |
  340.                  KeyPressMask | PointerMotionHintMask  | PointerMotionMask |
  341.          ButtonReleaseMask );
  342.     XMapWindow(dpy, win);
  343.     XFlush(dpy);
  344.     return(0);
  345. }
  346.  
  347.  
  348.  
  349. int
  350. getVideoFrame()
  351. {
  352.  VLInfoPtr info;
  353.  VLEvent vlEvent;
  354.  
  355.     newImg = False;
  356.     if (vlCheckEvent(svr, VLTransferCompleteMask, &vlEvent) == 0) {
  357.         if (debug)
  358.           printf("transfer event arrived\n");
  359.         while ((info = vlGetLatestValid(svr, buffer)) == 0); 
  360.         rgbFrame = vlGetActiveRegion(svr, buffer, info);
  361.         newImg = True;
  362.     }
  363. }
  364.  
  365.  
  366. void getMovieFrame()
  367. {
  368.     static int curFrame = 0;
  369.  
  370.     newImg = False;
  371.     if (mvReadFrames(imgTrack, curFrame, 1, frameSize, rgbFrame) < 0) {
  372.        fprintf(stderr, "could not read movie frame\n");
  373.        mvGetErrno();
  374.        exit(0); 
  375.     }
  376.  
  377.     if (++curFrame > movieLen - 1)
  378.       curFrame = 0;   
  379.     newImg = True;
  380. }
  381.  
  382.  
  383. grabAndSetTex()
  384.     if (grabNew) {
  385.       if (video) {
  386.         getVideoFrame();
  387.     if (!newImg)
  388.       return;
  389.       }
  390.       else 
  391.         getMovieFrame();
  392.  
  393.      if (bltImg)
  394.        lrectwrite(0, 0, imgWidth-1, imgHeight-1, rgbFrame);
  395.      else if (!moving)
  396.        texdef2d(1, RGB_COMP, imgWidth, imgHeight, (unsigned long *)rgbFrame, 
  397.                  1, texprops);
  398.     } 
  399.     
  400.     /*
  401.      * tell the system that we're done with that frame
  402.      */
  403.     if (video) {
  404.        gflush();
  405.        vlPutFree(svr, buffer);
  406.     }
  407.     
  408.     if (initTextureParams) {
  409.       initTextureParams = FALSE;
  410.       tevdef(1, 1, tevprops);
  411.       tevbind(TV_ENV0, 1);
  412.       texdef2d(1, RGB_COMP, imgWidth, imgHeight, (ulong *)rgbFrame, 1, texprops);
  413.       texbind(TX_TEXTURE_0, 1);
  414.     }
  415. }
  416.  
  417.  
  418. executeKey(int glKey)
  419. {
  420.        switch(glKey){
  421.          case XK_n:     minFiltIndex = ++minFiltIndex % 6;
  422.                     texprops[1] = minFilter[minFiltIndex];
  423.                     printf("min filter = %s\n",  
  424.                                          minFilterName[minFiltIndex]);
  425.                     break;
  426.                  case XK_m:     magFiltIndex = ++magFiltIndex % 2;
  427.                                 texprops[3] = magFilter[magFiltIndex];
  428.                                 printf("mag filter = %s\n",
  429.                                          magFilterName[magFiltIndex]);
  430.                               
  431.                                break;
  432.          case XK_c:    if (oneComp == TRUE) {
  433.                                   oneComp = FALSE;
  434.                                   printf("4 component texture\n");
  435.                     }
  436.                      else {
  437.                       oneComp = TRUE;
  438.                                   printf("1 component texture\n");
  439.                     }
  440.                   
  441.                   break;
  442.          case XK_g:   if (grabNew == TRUE) {
  443.                                   grabNew = FALSE;
  444.                                   printf("new img grabbing off\n");
  445.                     }
  446.                      else {
  447.                       grabNew = TRUE;
  448.                                   printf("new img grabbing on\n");
  449.                     }
  450.                  
  451.                   break;
  452.          case XK_b:   if (bltImg == TRUE) {
  453.                                   bltImg = FALSE;
  454.                                   printf("texture mapping on\n");
  455.                   initTextureParams = TRUE;                  
  456.                     }
  457.                      else {
  458.                       bltImg = TRUE;
  459.                                   printf("texture mapping off\n");
  460.                     }
  461.                   break;
  462.                  case XK_p:   if (reportPerf) {
  463.                   printf("Performance measuring: Off\n");
  464.                       reportPerf = FALSE;
  465.                 }
  466.                     else {
  467.                   printf("Performance measuring: On\n");
  468.                   printf("Performance calculated every 10 frames.\n");
  469.                   reportPerf = TRUE;
  470.                                   gettimeofday(&starttime);
  471.                                   nframes = 0;
  472.                                 }
  473.                     break;
  474.                  case XK_q:    if ( t1[0] == 1.0 ) {
  475.                   t1[0] = 2.0;
  476.                   t2[0] = 2.0;
  477.                   t2[1] = 2.0;
  478.                   t3[1] = 2.0;
  479.                 }
  480.                 else {
  481.                                   t1[0] = 1.0;
  482.                                   t2[0] = 1.0;
  483.                                   t2[1] = 1.0;
  484.                                   t3[1] = 1.0;
  485.                 }
  486.                   
  487.                   break;
  488.                  case XK_Escape:
  489.                             texbind(TX_TEXTURE_0, 0);
  490.                               tevbind(TV_ENV0, 0);
  491.                               /* winclose(vidmap); */
  492.                               exit(0);
  493.                               break;
  494.  
  495.          } /* end switch */
  496.   
  497. }
  498.  
  499.  
  500.  
  501. main(int argc, char** argv)
  502. {
  503.     short val;
  504.     int stat;
  505.     double perf;
  506.     int mousex, mousey, lastmousex, lastmousey;
  507.     int rotx, roty;
  508.     Boolean first = TRUE;
  509.     GLXconfig params[50];
  510.     GLXconfig* next;
  511.     GLXconfig* retconfig;
  512.     Window rwin, swin;
  513.     int rootx, rooty;
  514.     unsigned int btns;
  515.     int glKey;
  516.     KeySym ks;
  517.     int c;
  518.     static Matrix identity = { 1,0,0,0,
  519.                                0,1,0,0,
  520.                                0,0,1,0,
  521.                                0,0,0,1};
  522.     _progName = argv[0];
  523.  
  524.     while ((c = getopt(argc, argv, "pdv:b:lz:")) != EOF) {
  525.         switch(c) {
  526.         case 'v':
  527.             vin= atoi(optarg);
  528.         forced_node = 1;
  529.             break;
  530.         case 'b':
  531.             imageCount = atoi(optarg);
  532.             printf("buffer size = %d\n", imageCount);
  533.             break;
  534.         case 'z':
  535.             zoom = atoi(optarg);
  536.             break;
  537.         case 'l':
  538.         bltImg = TRUE;
  539.             break;
  540.         case 'd':
  541.         debug = TRUE;
  542.             break;
  543.         case 'p':
  544.         reportPerf = TRUE;
  545.             break;
  546.         }
  547.     }
  548.     
  549.     printControls();
  550.     
  551.     if (optind != argc) {
  552.       video = FALSE;
  553.       moviefn = argv[optind];
  554.     }
  555.     else
  556.       video = TRUE;
  557.       
  558.     dpy = XOpenDisplay(0);
  559.     if (!dpy) {
  560.         fprintf(stderr, "cannot open display\n");
  561.         return -1;
  562.     }
  563.  
  564.     scrn = DefaultScreen(dpy);
  565.  
  566.     xorg = 200;
  567.     xwidth = 320;
  568.     xmax = xorg + xwidth;
  569.     yorg = 100;
  570.     yheight = 240;
  571.     ymax = yorg + yheight;
  572.  
  573.     if (createVideoWindow(xwidth, yheight) < 0) {
  574.         fprintf(stderr, "could not create window\n");
  575.         exit(0);
  576.     }
  577.     
  578.     if (video)
  579.       pixmode(PM_TTOB, 1); 
  580.     else 
  581.       pixmode(PM_TTOB, 0);
  582.        
  583.     mmode(MPROJECTION);
  584.     loadmatrix(identity);
  585.     perspective(600, 1., 1., 1000.);
  586.     mmode(MVIEWING);
  587.     loadmatrix(identity);
  588.  
  589.     translate(0., 0., transy);  /* Move poly away from viewer */
  590.  
  591.     /** wait til window is up before doing anything else ***/
  592.     while (1) { 
  593.      XNextEvent(dpy,&event);
  594.      if (event.type == Expose)
  595.      break;
  596.     }
  597.  
  598.     if (video)
  599.       initVideo();
  600.     else {
  601.       initMovie(); 
  602.       rotate(-1800,'z');
  603.       rotate(-1800,'y'); 
  604.     }
  605.     
  606.     grabAndSetTex();
  607.  
  608.     mousex = xwidth / 2;
  609.     mousey = yheight / 2;
  610.  
  611.     while ( TRUE ){
  612.      if (XPending(dpy)) {
  613.       XNextEvent(dpy,&event);
  614.       switch (event.type) {
  615.         case KeyPress:
  616.            ks = XLookupKeysym( &event.xkey, 0 );
  617.        executeKey(ks);
  618.            break;
  619.        
  620.     case ButtonPress:
  621.        buttonIsPressed = True;
  622.        break;
  623.        
  624.     case ButtonRelease:
  625.        buttonIsPressed = False;
  626.        break;
  627.        
  628.         case MotionNotify:
  629.        XQueryPointer( dpy, win, &rwin, &swin, &rootx, &rooty, 
  630.                            &mousex, &mousey, &btns);
  631.            break;
  632.        
  633.         case ConfigureNotify:           /* window was resized */
  634.                     /* inform movie lib window was resized.  As a side
  635.                      * effect, this also resizes the GL viewport */
  636.         xwidth = event.xconfigure.width;
  637.         yheight = event.xconfigure.height;
  638.         reshapeviewport();
  639.     printf("window resized\n");
  640.     break;
  641.  
  642.       }
  643.      }
  644.  
  645.         cpack(0x00000000);
  646.     clear();
  647.  
  648.         moving = FALSE;
  649.         if (mousex != lastmousex) {
  650.       lastmousex = mousex;
  651.           rotx = (xwidth / 2) - mousex;
  652.       moving = TRUE;
  653.     }
  654.     
  655.         if (mousey != lastmousey) {
  656.       if (buttonIsPressed) {
  657.           transy = .6 * (lastmousey - mousey);
  658.               translate(0., 0., transy);
  659.               lastmousey = mousey;
  660.       }
  661.       else {
  662.               lastmousey = mousey;
  663.               roty = (yheight / 2) - mousey;
  664.       }
  665.       moving = TRUE;
  666.         }
  667.  
  668.         grabAndSetTex();
  669.  
  670.       if (!bltImg) {
  671.         cpack(0xffffffff);
  672.  
  673.     pushmatrix();
  674.  
  675.     rotate(rotx * 10,'y');
  676.     rotate(-roty * 10,'x');
  677.  
  678.     bgnpolygon();
  679.     t2f(t0);   v3f(v0);
  680.     t2f(t1);   v3f(v1);
  681.     t2f(t2);   v3f(v2);
  682.     t2f(t3);   v3f(v3);
  683.     endpolygon();
  684.  
  685.     popmatrix();
  686.     swapbuffers();
  687.       }
  688.       else if (newImg) {
  689.     swapbuffers();
  690.       }
  691.       
  692.       if ((!bltImg || newImg) && reportPerf) {
  693.         if (++nframes >= 10) {
  694.            gettimeofday(&endtime);
  695.            perf = (double)(nframes)
  696.                  / (((double)((endtime.tv_sec - starttime.tv_sec) * 1000000
  697.                    + (endtime.tv_usec - starttime.tv_usec))) / 1000000.0);
  698.            nframes = 0;
  699.            starttime = endtime;
  700.            fprintf(stderr, "%5.2f Frames Per Second\n", perf);
  701.         }
  702.       }
  703.  
  704.     }
  705.     texbind(TX_TEXTURE_0, 0); 
  706. }
  707.